using System;
using System.IO;
using System.Reflection;
using NMock2;

namespace NMockExtensions
{
    public class GenericMethodMatcher : Matcher
    {
        private readonly Type[] argumentTypes;
        private readonly string methodName;

        public GenericMethodMatcher(
            string methodName,
            params Type[] argumentTypes)
        {
            this.methodName = methodName;
            this.argumentTypes = argumentTypes;
        }

        public override void DescribeTo(TextWriter writer)
        {
            writer.Write(methodName);
        }

        public override bool Matches(object o)
        {
            MethodInfo method = o as MethodInfo;

            return (method != null
                    && method.Name == methodName
                    && (
                        (method.ContainsGenericParameters && method.GetGenericArguments().Length == argumentTypes.Length)
                        ||
                        (!method.ContainsGenericParameters && ArraysMatch(method.GetGenericArguments(), argumentTypes))
                    )
                  );
        }

        private static bool ArraysMatch(Type[] types, Type[] argumentTypes)
        {
            if (types.Length != argumentTypes.Length) return false;
            for (int i = 0; i < argumentTypes.Length; i++)
            {
                if (argumentTypes[i] != types[i]) return false;
            }
            return true;
        }
    }
}